/* *
 * --ライセンスについて--
 *
 * 「本ファイルの内容は Mozilla Public License Version 1.1 (「本ライセンス」)
 * の適用を受けます。
 * 本ライセンスに従わない限り本ファイルを使用することはできません。
 * 本ライセンスのコピーは http://www.mozilla.org/MPL/ から入手できます。
 *
 * 本ライセンスに基づき配布されるソフトウェアは、「現状のまま」で配布されるものであり、
 * 明示的か黙示的かを問わず、いかなる種類の保証も行われません。
 * 本ライセンス上の権利および制限を定める具体的な文言は、本ライセンスを参照してください。
 *
 * オリジナルコードおよび初期開発者は、N_H (h.10x64@gmail.com) です。
 *
 * N_H によって作成された部分の著作権表示は次のとおりです。
 *
 * Copyright (C) 2011 - 2012
 *
 * このファイルの内容は、上記に代えて、
 * GNU General License version2 以降 (以下 GPL とする)、
 * GNU Lesser General Public License Version 2.1 以降 (以下 LGPL とする)、
 * の条件に従って使用することも可能です。
 * この場合、このファイルの使用には上記の条項ではなく GPL または LGPL の条項が適用されます。
 * このファイルの他者による使用を GPL または LGPL の条件によってのみ許可し、
 * MPL による使用を許可したくない対象者は、上記の条項を削除することでその意思を示し、
 * 上記条項を GPL または LGPL で義務付けられている告知およびその他の条項に置き換えてください。
 * 対象者が上記の条項を削除しない場合、
 * 受領者は MPL または GPL または LGPL ライセンスのいずれによってもこのファイルを
 * 使用することができます。」
 *
 * -- License --
 *
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License。You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND、either express or implied。See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *   N_H (h.10x64@gmail.com).
 *
 * Portions created by the Initial Developer are Copyright (C) 2011 - 2012
 * the Initial Developer。All Rights Reserved.
 *
 * Alternatively、the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL")、or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above。If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL、and not to allow others to
 * use your version of this file under the terms of the MPL、indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL。If you do not delete
 * the provisions above、a recipient may use your version of this file under
 * the terms of any one of the MPL、the GPL or the LGPL.
 *
 * */
package com.magiciansforest.audio.vst.binaural;

import com.magiciansforest.audio.vst.binaural.sixdofstreamer.DataReadEvent;
import com.magiciansforest.audio.vst.binaural.sixdofstreamer.DataReadListener;
import com.magiciansforest.audio.vst.binaural.sixdofstreamer.SixDOFStreamer;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import jvst.wrapper.VSTPluginAdapter;
import jvst.wrapper.VSTPluginGUIAdapter;
import jvst.wrapper.gui.VSTPluginGUIRunner;

/**
 *
 * @author N_H <h.10x64@gmail.com>
 */
public class BinauralGUI extends VSTPluginGUIAdapter implements ChangeListener, DataReadListener {

    private static final String SIX_DOF_DATA_REGEX = "(-?\\d+\\.\\d+)\\s(-?\\d+\\.\\d+)\\s(-?\\d+\\.\\d+)\\s(-?\\d+\\.\\d+)\\s(-?\\d+\\.\\d+)\\s(-?\\d+\\.\\d+)";
    private static final Pattern SIX_DOF_DATA_PATTERN = Pattern.compile(SIX_DOF_DATA_REGEX);
    private static final int GROUP_X = 1;
    private static final int GROUP_Y = 2;
    private static final int GROUP_Z = 3;
    private static final int GROUP_DX = 4;
    private static final int GROUP_DY = 5;
    private static final int GROUP_DZ = 6;
    private static final int SPAN = 100;
    private Binaural binaural;
    private SoundPositionControlPanel control;
    private SoundEnvironment env = null;
    private Matrix4 observerZeroPosture = null;
    private boolean resetObserverPosture = true;

    public BinauralGUI(VSTPluginGUIRunner r, VSTPluginAdapter plugin) {
        super(r, plugin);
        if (plugin instanceof Binaural) {
            this.binaural = (Binaural) plugin;
            createWindow();
            binaural.setGUI(this);
            
            try {
                SixDOFStreamer streamer = new SixDOFStreamer();
                streamer.addDataReadListener(this);
                streamer.start();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    @Override
    public void stateChanged(ChangeEvent e) {
        if (e.getSource().equals(env)) {
            Spherical pos = env.getSoundPosition();
            binaural.setSoundPosition(Math.toDegrees(pos.elev), Math.toDegrees(pos.azim), pos.dist);
        }
    }

    @Override
    public void DataRead(DataReadEvent e) {
        Matcher m = SIX_DOF_DATA_PATTERN.matcher(e.getData());
        if (m.matches()) {
            double dx = Double.parseDouble(m.group(GROUP_X));
            double dy = Double.parseDouble(m.group(GROUP_Y));
            double dz = -Double.parseDouble(m.group(GROUP_Z));
            double rx = -Math.toRadians(Double.parseDouble(m.group(GROUP_DX)));
            double ry = -Math.toRadians(Double.parseDouble(m.group(GROUP_DY)));
            double rz = Math.toRadians(Double.parseDouble(m.group(GROUP_DZ)));

            if (env != null) {
                Matrix4 observerPosture;
                if (rx == 0 && ry == 0 && rz == 0 && dx == 0 && dy == 0 && dz == 0) {
                    resetObserverPosture = true;
                    observerPosture = new Matrix4(
                            1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1);
                } else {
                    Matrix4 readData = Matrix4.getMatrix(rx, ry, rz, dx, dy, dz, Matrix4.ZXY);
                    if (resetObserverPosture || observerZeroPosture == null) {
                        observerZeroPosture = new Matrix4(readData);
                        resetObserverPosture = false;
                    }
                    observerPosture = Matrix4.getMul(readData, Matrix4.getReverse(observerZeroPosture));
                }
                env.setObserverPosture(observerPosture);
                
                env.update(0);
            }
        }
    }

    public void update(double dt) {
        env.update(dt);
    }
    
    public SoundEnvironment getSoundEnvironment() {
        return this.env;
    }

    private void createWindow() {
        setResizable(true);

        env = new SoundEnvironment(10, 10, 10);
        env.addChangeListener(this);

        control = new SoundPositionControlPanel(binaural, env);
        control.setSize(480, 480);
        control.setPreferredSize(new Dimension(480, 480));
        control.addChangeListener(this);
        setLayout(new BorderLayout());
        add(control, BorderLayout.CENTER);
        pack();
    }
}
